import log from '../../config/logger'
import { getAccountModel, getVersionModel, VersionType, computeAccountHash, AccountType } from '../../model'
import { Context, BaseService } from '../Service'
import { ServiceNo } from '../ServiceNo'

class AccountService extends BaseService {
  async addVersion (ctx: Context, reqBody: any) {
    const Version = getVersionModel(ctx.user.versionTable || 'version')
    const Account = getAccountModel(ctx.user.accountTable || 'account')

    const { versionName, accounts }: {
      versionName: string,
      accounts: AccountType[]
    } = reqBody
    for (const acc of accounts) {
      acc.hash = computeAccountHash(acc)
    }

    // 目前的最新版本
    const latestVersion: any = await Version.findOne({
      latest: 0
    }).sort({
      createTime: 'desc'
    })

    // 创建新的最新版本
    const version: VersionType = {
      versionName
    }

    const newVersion = new Version(version)

    const newLatestVersion: any = await newVersion.save()

    const accountsToBeSave: AccountType[] = []

    if (latestVersion) {
      // 目前的最新版本改为非最新版本
      await Version.updateOne({
        versionName: latestVersion.versionName
      }, {
        $set: {
          latest: 1
        }
      })

      // 判断现有版本是否需要更新 并按需更改版本信息
      for (const acc of accounts) {
        const a: any = await Account.findOne({
          hash: acc.hash
        })
        if (!a) {
          await Account.updateOne({
            accountName: acc.accountName,
            version: 'lt'
          }, {
            $set: {
              version: latestVersion.versionName
            }
          })
          accountsToBeSave.push(acc)
        }
      }
    } else {
      for (const acc of accounts) {
        accountsToBeSave.push(acc)
      }
    }

    // 保存新增数据
    for (const acc of accountsToBeSave) {
      log.info(`saving ${acc.accountName}`)
      await new Account(acc).save()
    }

    ctx.body = {
      versionName: newLatestVersion.versionName,
      latest: newLatestVersion.latest === 0,
      createTime: newLatestVersion.createTime,
      lastMod: newLatestVersion.lastMod
    }
  }

  async listVersion (ctx: Context, reqBody: any) {
    const Version = getVersionModel(ctx.user.versionTable || 'version')
    const Account = getAccountModel(ctx.user.accountTable || 'account')
    const { version } = reqBody
    let v: any
    if (version) {
      v = await Version.findOne({
        versionName: version
      }).sort({
        createTime: 'desc'
      })
    } else {
      v = await Version.findOne({
        latest: 0
      }).sort({
        createTime: 'desc'
      })
    }

    const latestAccounts: any[] = await Account.find({
      version: 'lt'
    }, { _id: 0, hash: 0, version: 0, createTime: 0 }).sort('accountName')

    const accountMap: any = {}
    latestAccounts.forEach(acc => {
      accountMap[acc.accountName] = acc
    })

    if (v.latest !== 0) {
      const versionAccounts: any[] = await Account.find({
        version: v.versionName
      }, { _id: 0, hash: 0, version: 0, createTime: 0 }).sort('accountName')
      versionAccounts.forEach(acc => {
        accountMap[acc.accountName] = acc
      })
    }

    ctx.body = {
      version: {
        versionName: v.versionName,
        latest: v.latest === 0,
        createTime: v.createTime,
        lastMod: v.lastMod
      },
      accountMap
    }
  }

  async getLatestVersion (ctx: Context) {
    const Version = getVersionModel(ctx.user.versionTable || 'version')
    const v: any = await Version.findOne({
      latest: 0
    }).sort({
      createTime: 'desc'
    })
    ctx.body = {
      versionName: v.versionName,
      latest: v.latest === 0,
      createTime: v.createTime,
      lastMod: v.lastMod
    }
  }

  async listAllVersions (ctx: Context, reqBody: any) {
    const { page = 1, pageSize = 10 }: {
      page: number,
      pageSize: number
    } = reqBody
    if (pageSize > 100) {
      ctx.throw(400, 'pageSize max allowed 100')
    }
    const Version = getVersionModel(ctx.user.versionTable || 'version')
    ctx.body = await Version.find({}, { _id: 0, __v: 0 }).sort({
      createTime: 'desc'
    }).skip((page - 1) * pageSize).limit(pageSize)
  }

  init () {
    let methodNo = 100
    this.addServiceInterface({
      methodNo: `${methodNo++}`,
      method: this.listVersion,
      methodDesc: 'list all account at this version'
    }).addServiceInterface({
      method: this.addVersion,
      methodNo: `${methodNo++}`,
      methodDesc: 'add a new version with some accounts'
    }).addServiceInterface({
      method: this.getLatestVersion,
      methodNo: `${methodNo++}`,
      methodDesc: 'get the latest version info'
    }).addServiceInterface({
      method: this.listAllVersions,
      methodNo: `${methodNo++}`,
      methodDesc: 'list all versions with page parameter: [page(=1), pageSize(<=100,default is 10)]'
    })
  }
}

export default new AccountService(ServiceNo.account)
